package com.zan.backend.aspect;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

/**
 * @Author Zan
 * @Create 2024/9/9 15:39
 * @ClassName: LogAspect
 * @Description : 日志管理的切面类
 */
@Aspect
@Component
@Slf4j
public class LogAspect {

    private static final int maxPrintLength = 2000;

    /**
     * 指定切入点为Controller
     */
    @Pointcut("@within(org.springframework.stereotype.Controller) || @within(org.springframework.web.bind.annotation.RestController)")
    public void weblogPointcut() {
    }

    /**
     * 统一处理日志，以及记录接口处理时间
     *
     * @param joinPoint
     * @return 不关注回调结果，http返回200即可
     */
    @SneakyThrows
    @Around("weblogPointcut()")
    public Object logAroundApi(ProceedingJoinPoint joinPoint) {

        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        String method = joinPoint.getSignature().toShortString();
        // 记录用时
        long begin = System.currentTimeMillis();
        try {
            // 记录请求参数及响应内容
            String args = Arrays.toString(joinPoint.getArgs());
            if (StringUtils.isNotEmpty(args) && args.length() > maxPrintLength) {
                args = args.substring(0, maxPrintLength);
            }

            log.info("接口入参：servlet path request url: [{}]{}, method: {}, args: {}",
                    request.getMethod(), request.getRequestURL(), method, args);
            Object response = joinPoint.proceed();

            String responseString = "";
            if (response != null) {
                responseString = response.toString();
                if (responseString.length() > maxPrintLength) {
                    responseString = responseString.substring(0, maxPrintLength);
                }
            }
            log.info("接口出参：接口耗时：{}ms, servlet path request url: [{}]{}, method: {}, response: {}",
                    (System.currentTimeMillis() - begin), request.getMethod(), request.getRequestURL(), method, responseString);

            return response;
        } catch (Throwable e) {
            // 在抛出异常前日志记录下异常信息
            log.error("接口异常：servlet path request url: [{}]{}, 接口耗时：{}ms, message:{}",
                    request.getMethod(), request.getRequestURL(), (System.currentTimeMillis() - begin), e.getMessage(), e);
            throw e;
        }
    }
}
